package com.shanlitech.bluetooth;

import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;

import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.shanlitech.bluetooth.calibration.CalibrationScanner;
import com.shanlitech.bluetooth.map.ImageLoader;
import com.shanlitech.bluetooth.map.Map2D;
import com.shanlitech.bluetooth.map.MapMarker;
import com.shanlitech.bluetooth.map.Size;
import com.shanlitech.bluetooth.sample.SampleDatabase;
import com.shanlitech.bluetooth.sample.SampleRecorder;
import com.shanlitech.lbs.geometry.Point2D;
import com.shanlitech.lbs.map.BleBeacon;
import com.shanlitech.lbs.map.CalibrationPoint;
import com.shanlitech.lbs.map.LbsDatabase;
import com.shanlitech.lbs.map.MapFlat;
import com.shanlitech.lbs.sample.CalibrationSample;
import com.shanlitech.lbs.types.RssiRecord;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link CalibrationFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class CalibrationFragment extends Fragment {
    private static final String TAG = "SLBluetooth";

    private Map2D mMap;
    private Button mBtnCalibration;
    private Button mBtnRebuild;
    private Button mBtnSave;
    private MapMarker mMarker;
    private MapFlat mFlat = null;
    private CalibrationSample mLastSample = null;


    public CalibrationFragment() {
        // Required empty public constructor
    }

    public static CalibrationFragment newInstance() {
        CalibrationFragment fragment = new CalibrationFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_calibration, container, false);
        mMap = view.findViewById(R.id.map);
        mBtnCalibration = view.findViewById(R.id.button_calibration);
        mBtnRebuild = view.findViewById(R.id.button_rebuild_cp);
        mBtnSave = view.findViewById(R.id.button_save);

        mFlat = AppContext.getFlat();
        mBtnCalibration.setOnClickListener(view0 -> {
            final CalibrationScanner scanner = CalibrationScanner.getInstance(getContext());
            if( scanner.isStart() ) {
                stopCalibration();
            } else {
                startCalibration();
            }
        });
        mBtnRebuild.setOnClickListener(view0 -> {
            rebuildCalibrationPoints();
        });

        mBtnSave.setOnClickListener(view0 -> {
            saveCalibrationPoint();
        });
        mBtnSave.setEnabled(false);

        MapMarker.Builder builder = new MapMarker.Builder(this.getContext(),"marker");
        mMarker = builder.loadImage("res://com.shanlitech.bluetooth:drawable/marker")
                .setAnchor(MapMarker.ANCHOR_BOTTOM_MIDDLE)
                .setDrawSize(80,80)
                .setDraggable(true)
                .setTextMode(MapMarker.TEXT_COORDINATE)
                .setTextSize(20.f)
                .setTextColor(Color.BLUE)
                .setCoordinate(AppContext.getLocation())
                .build();
        mMap.addStaticMarker(mMarker);
        showCalibrationPoints();
        //mMap.initialize(true,MapMarker.TEXT_NAME_COORDINATE);

        return view;
    }

    private void showCalibrationPoints() {
        mMap.loadBeacon(mFlat,true,MapMarker.TEXT_NAME);
        final List<CalibrationPoint> cps = mFlat.getCalibrationPoints();
        for(CalibrationPoint cp : cps) {
            /*
            MapMarker.Builder builder = new MapMarker.Builder(this.getContext(),cp.uuid);
            MapMarker marker = builder.loadImage("res://com.shanlitech.bluetooth:drawable/camera")
                    .setAnchor(MapMarker.ANCHOR_CENTER)
                    .setDrawSize(80,80)
                    .setDraggable(false)
                    .setTextMode(MapMarker.TEXT_NONE)
                    .setTextSize(20.f)
                    .setTextColor(Color.BLUE)
                    .setCoordinate(cp.location.x,cp.location.y)
                    .build();
            mMap.addDynamicMarker(marker);
             */
            mMap.addDynamicRound(cp.location.x,cp.location.y,cp.getInfluence(),Color.GREEN);
        }
    }

    private void showBeacons(HashSet<BleBeacon> beacons) {
        for(BleBeacon beacon : beacons) {
            MapMarker.Builder builder = new MapMarker.Builder(this.getContext(),beacon.uuid);
            MapMarker marker = builder.loadImage("res://com.shanlitech.bluetooth:drawable/beacon")
                    .setAnchor(MapMarker.ANCHOR_BOTTOM_MIDDLE)
                    .setDrawSize(80,80)
                    .setDraggable(false)
                    .setTextMode(MapMarker.TEXT_NAME)
                    .setTextSize(20.f)
                    .setTextColor(Color.BLUE)
                    .setCoordinate(beacon.location.x,beacon.location.y)
                    .build();
            mMap.addDynamicMarker(marker);
        }
        Log.d(TAG,"show " + beacons.size() + " beacons");
    }

    private void startCalibration() {
        final CalibrationScanner scanner = CalibrationScanner.getInstance(getContext());
        if( scanner.isStart() ) {
            return;
        }
        if( ! checkRecord() ) {
            Log.d(TAG,"checkRecord fail");
            return;
        }
        final Point2D location = mMarker.getCoordinate();

        scanner.start(mFlat,location,14,30, this::onUpdate);

        mMap.clearDynamic();
        showBeacons(scanner.getBeacons());
        mMap.invalidate();
        mBtnSave.setEnabled(false);
        mBtnRebuild.setEnabled(false);
        mBtnCalibration.setText(R.string.stop_calibration);
    }

    private void stopCalibration() {
        final CalibrationScanner scanner = CalibrationScanner.getInstance(getContext());
        if( !scanner.isStart() ) {
            return;
        }
        mLastSample = scanner.build();
        scanner.stop();
        mBtnRebuild.setEnabled(true);
        mBtnCalibration.setText(R.string.start_calibration);

        isValidCalibrationSample();
    }

    private boolean isValidCalibrationSample() {
        if( mLastSample != null ) {
            mBtnSave.setEnabled(true);
            return true;
        } else {
            mBtnSave.setEnabled(false);
            return false;
        }
    }


    private void onUpdate(float complete,HashMap<BleBeacon,Float> beaconComplete) {
        final Size drawSize = new Size(80, 80);
        for (BleBeacon beacon : beaconComplete.keySet()) {
            Float bc = beaconComplete.get(beacon);
            assert bc != null;
            MapMarker marker = mMap.getDynamicMarker(beacon.uuid);
            assert marker != null;

            if (bc >= 1.0f) {
                marker.setImage(ImageLoader.load(getContext(), "res://com.shanlitech.bluetooth:drawable/signal_green"), MapMarker.ANCHOR_BOTTOM_MIDDLE, drawSize);
            } else if (bc > 0.75f) {
                marker.setImage(ImageLoader.load(getContext(), "res://com.shanlitech.bluetooth:drawable/signal_blue"), MapMarker.ANCHOR_BOTTOM_MIDDLE, drawSize);
            } else if (bc >= 0.5f) {
                marker.setImage(ImageLoader.load(getContext(), "res://com.shanlitech.bluetooth:drawable/signal_gold"), MapMarker.ANCHOR_BOTTOM_MIDDLE, drawSize);
            } else if (bc >= 0.25f) {
                marker.setImage(ImageLoader.load(getContext(), "res://com.shanlitech.bluetooth:drawable/signal_red"), MapMarker.ANCHOR_BOTTOM_MIDDLE, drawSize);
            }
        }
        mMap.invalidate();

        if( complete >= 1.0f ) {
            stopCalibration();
        }
    }

    private void saveCalibrationPoint() {
        if( ! isValidCalibrationSample() ) {
            return;
        }
        final CalibrationPoint cp = CalibrationPoint.create(mLastSample);
        if( cp != null ) {
            mFlat.addCalibrationPoint(cp);
            MapBuilder.writeFile(getContext());
            SampleRecorder.save(getContext(),mLastSample);
        }
        mLastSample = null;
        mBtnSave.setEnabled(false);

        mMap.clearDynamic();
        showCalibrationPoints();
        mMap.invalidate();
    }

    private boolean checkRecord() {
        if( ! isValidCalibrationSample() ) {
            return true;
        }
        AlertDialog dialog = new AlertDialog.Builder(this.getContext())
                .setMessage(R.string.calibration_auto_save)
                //设置对话框的按钮
                .setNegativeButton(R.string.drop, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        mLastSample = null;
                        showCalibrationPoints();
                    }
                })
                .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        saveCalibrationPoint();
                    }
                }).create();
        dialog.show();
        return false;
    }

    private void rebuildCalibrationPoints() {
        final LbsDatabase database = LbsDatabase.getInstance();
        database.clearCalibrationPoints();

        final List<CalibrationSample> samples = SampleDatabase.getInstance(getContext()).getCalibration();
        for(CalibrationSample sample : samples) {
            final MapFlat flat = database.getFlat(sample.partition,sample.floor);
            if( flat != null ) {
                final CalibrationPoint cp = CalibrationPoint.create(sample);
                flat.addCalibrationPoint(cp);
            }
        }
        MapBuilder.writeFile(getContext());
    }
}